package wg

import (
	"fmt"
	"math/rand"
	"net"
	"os"
	"regexp"
	"strings"
	"time"
	"io/ioutil"
	"os/exec"
	"github.com/go-ping/ping"
	"golang.org/x/sys/windows"
)

var (
	reSpace = regexp.MustCompile(`\s+`)
)

func GetIfaceListenPortString(iface string) (string, error) {
	r, err := run("wg", "show", iface, "listen-port")
	if err != nil {
		return "", fmt.Errorf("wg[%s]interface端口获取失败:%s", iface, err.Error())
	}
	return r, nil
}

func SetPeerEndpointNew(iface string, peer, endpoint string) error {
	p := fmt.Sprintf("wg set %s peer %s persistent-keepalive 15 endpoint %s", iface, peer, endpoint)
	_, err := run("sh", "-c", p)
	//_, err := run_windows("wg","set",iface,"peer",peer,"persistent-keepalive","15","endpoint",endpoint) 
	if err != nil {
		return err
	}
	return nil
}

func AddInterface(name string) error {
	//if err := clearP2PWg(); err != nil {
	//	return err
	//}
	if err := CreateWg(name); err != nil {
		return err
	}
	time.Sleep(time.Second * 1)
	if err := SetMtu(name); err != nil {
		return err
	}
	return nil
}

func clearP2PWg() error {
	// wg, err := wgctrl.New()
	// defer wg.Close()
	// if err != nil {
	// 	return fmt.Errorf(`wg 连接失败:%s`, err.Error())
	// }
	// devices, err := wg.Devices()
	// if err != nil {
	// 	return fmt.Errorf(`wg 获取配置失败:%s`, err.Error())
	// }
	// for _, device := range devices {
	// 	if strings.HasPrefix(device.Name, "fsP2P_") {
	// 		err := DelWg(device.Name)
	// 		if err != nil {
	// 			return fmt.Errorf(`wg 删除配置失败:%s`, err.Error())
	// 		}
	// 	}
	// }
	return nil
}

func DelWg(name string) error {
	_, err := run(
		"ip", "link", "delete", name)
	if err != nil {
		return fmt.Errorf("删除 wg[%s] 失败:%s", name, err.Error())
	}
	return nil
}

func CreateWg(name string) error {
	_, err := run(
		"wireguard-go", name)
	if err != nil {
		return fmt.Errorf("创建 wg[%s] 失败:%s", name, err.Error())
	}
	return nil
}
//需要创建一个临时文件
func setWireguardPrivateKey(interfaceName string, privateKey string) error {
	// 创建临时文件
	tmpFile, err := ioutil.TempFile("", "private-key")
	if err != nil {
		return err
	}

	// 将私钥写入临时文件
	_, err = tmpFile.WriteString(privateKey)
	if err != nil {
		tmpFile.Close()
		os.Remove(tmpFile.Name())
		return err
	}

	// 关闭临时文件
	err = tmpFile.Close()
	if err != nil {
		os.Remove(tmpFile.Name())
		return err
	}

	// 设置私钥
	//_ ,err = run_windows("wg.exe", "set", interfaceName, "private-key", tmpFile.Name())
	//err = cmd.Run()
	if err != nil {
		os.Remove(tmpFile.Name())
		return err
	}

	// 删除临时文件
	os.Remove(tmpFile.Name())

	return nil
}

func SetPrivateKey(name, privateKey, publicKey string) error {
	r, err := run("sh", "-c",
		fmt.Sprintf("echo %s | wg set %s private-key /dev/stdin", privateKey, name))
	//err:=setWireguardPrivateKey(name, privateKey)
	//r, err := run_windows("wg","set",name ,"private-key",privateKey)
	if err != nil {
		return fmt.Errorf("设置 wg[%s] private key 失败:%s", r, err)
	}
	return nil
}

func GetPeers(name string) ([]string, error) {
	r, err := run(
		"wg", "show", name, "peers")
	if err != nil {
		return nil, fmt.Errorf("获取 wg[%s] peers 失败:%s", name, err.Error())
	}
	peers := make([]string, 0)
	for _, it := range strings.Split(r, "\n") {
		it = strings.TrimSpace(it)
		if it == "" {
			continue
		}
		peers = append(peers, it)
	}
	return peers, nil
}

func DelPeer(name, publicKey string) error {
	p := fmt.Sprintf("wg set %s peer %s remove", name, publicKey)
	_, err := run("sh", "-c", p)
	//_, err := run_windows("wg","set",name ,"peer",publicKey,"remove")
	if err != nil {
		return fmt.Errorf("删除 wg[%s] peer[%s] 失败:%s", name, publicKey, err.Error())
	}
	return nil
}

func AddPeer(name, publicKey, addr, allowedIps string) error {
	p := fmt.Sprintf("wg set %s peer %s endpoint %s persistent-keepalive 15 allowed-ips %s", name, publicKey, addr, allowedIps)
	_, err := run(
		"sh", "-c", p)
	//_, err := run_windows("wg","set",name ,"peer",publicKey,"endpoint",addr,"persistent-keepalive","15","allowed-ips",allowedIps)
	if err != nil {
		return fmt.Errorf("添加 wg[%s] peer[%s] 失败:%s", name, publicKey, err.Error())
	}
	return nil
}


func addIPAddress(interfaceName string, ipAddress string) error {
	cmd := exec.Command("netsh", "interface", "ipv4", "add", "address", "name="+interfaceName, "address="+ipAddress)
	err := cmd.Run()
	if err != nil {
		return err
	}
	return nil
}

func SetInterfaceIp(name, ip string) error {
	//r, err := run("ip", "addr", "add", ip, "dev", name)
	err :=addIPAddress(name,ip)
	if err != nil {
		return fmt.Errorf("设置 wg[%s] ip 失败:%s", name,err)
	}
	return nil
}

func StartInterface(name string) error {
	/*
	r, err := run("ip", "link", "set", name, "up")
	if err != nil {
		return fmt.Errorf("启动 wg[%s] 失败:%s", name, r)
	}
	return nil
	*/
	cmd := exec.Command("netsh", "interface", "set", "interface", name, "admin=enable")
	err := cmd.Run()
	if err != nil {
		return err
	}
	return nil
}

func GetRtt(ip string) (string, error) {
	pinger, err := ping.NewPinger(ip)
	if err != nil {
		return "", err
	}
	pinger.SetPrivileged(true)
	pinger.Count = 1
	pinger.Timeout = time.Second * 1
	err = pinger.Run()
	if err != nil {
		return "", err
	}
	stats := pinger.Statistics()
	return fmt.Sprintf(`%d`, stats.AvgRtt.Milliseconds()), nil
}

func ClearIptables(name string) error {
	p := fmt.Sprintf(`iptables -t nat -S POSTROUTING | grep "%s" | sed 's/-A/-D/' | xargs -I {} sh -c "iptables -t nat {}"`, name)
	_, err := run(
		"sh", "-c", p)
	if err != nil {
		return fmt.Errorf("清除 iptables 失败:%s", err.Error())
	}
	p2 := fmt.Sprintf(`iptables -S FORWARD | grep "%s" | sed 's/-A/-D/' | xargs -I {} sh -c "iptables {}"`, name)
	_, err = run(
		"sh", "-c", p2)
	if err != nil {
		return fmt.Errorf("清除 iptables 失败:%s", err.Error())
	}
	return nil
}

func AddIptables(name, networkCard string) error {
	p := fmt.Sprintf(`iptables -A FORWARD -i %s -j ACCEPT -m comment --comment "%s"; iptables -A FORWARD -o %s -j ACCEPT -m comment --comment "%s"; iptables -t nat -A POSTROUTING -o %s -j MASQUERADE -m comment --comment "%s"; iptables -t nat -A POSTROUTING -o %s -j MASQUERADE -m comment --comment "%s"`, name, name, name, name, name, name, networkCard, name)
	_, err := run(
		"sh", "-c", p)
	if err != nil {
		return fmt.Errorf("添加 iptables 失败:%s", err.Error())
	}
	return nil
}

func WriteBird(name, path string) error {
	ip := getRandomIp(false)
	if ip == `` {
		return fmt.Errorf("bird ip 获取失败")
	}
	content := fmt.Sprintf(`log syslog all;
router id %s;
protocol device {
        scan time 10;
}
protocol direct {
      ipv4;
      interface "*";
}
protocol kernel{
    ipv4 {
        export all;
    };
}
protocol ospf v2 MYOSPF4 {
    ipv4{
        export where source ~ [ RTS_DEVICE, RTS_STATIC, RTS_OSPF, RTS_OSPF_IA, RTS_OSPF_EXT1, RTS_OSPF_EXT2];
        import all;
    };
    area 0 {
        interface "%s" {
            cost 100;        
            bfd on;
            type ptp;
        };
    };
}
protocol bfd {
        interface "*" {
                min rx interval 10ms;
                min tx interval 100ms;
                idle tx interval 1s;
                multiplier 10;
        };
}`, ip, name)
	os.Remove(path)
	f, err := os.Create(path)
	if err != nil {
		return fmt.Errorf("创建[%s]失败:%s", path, err.Error())
	}
	_, err = f.WriteString(content)
	if err != nil {
		return fmt.Errorf("写入[%s]失败:%s", path, err.Error())
	}
	f.Close()
	return refreshBird()
}

func refreshBird() error {
	_, err := run("birdc", "configure")
	if err != nil {
		return fmt.Errorf("birdc configure 失败:%s", err.Error())
	}
	return nil
}

func getRandomIp(deepFind bool) string {
	interfaces, err := net.Interfaces()
	if err != nil {
		return ``
	}
	ips := make([]string, 0)
	for _, v := range interfaces {
		if !deepFind {
			if !strings.HasPrefix(v.Name, `e`) {
				continue
			}
		}
		addrs, err := v.Addrs()
		if err != nil {
			continue
		}
		for _, addr := range addrs {
			ip, _, err := net.ParseCIDR(addr.String())
			if err != nil {
				continue
			}
			ipv4 := ip.To4()
			if ipv4 != nil && ipv4.String() != `127.0.0.1` {
				ips = append(ips, ipv4.String())
			}
		}
	}
	if len(ips) == 0 {
		return ``
	}
	//随机选择一个ip
	ip := ips[rand.Intn(len(ips))]
	if len(ip) == 0 {
		if deepFind {
			return ``
		}
		return getRandomIp(true)
	}
	return ip
}

func GetOsName() (error, string) {
	r, err := run("uname", "-a")
	if err != nil {
		return fmt.Errorf("获取系统信息失败:%s", err.Error()), ``
	}
	if r != `` {
		//Linux hecs-99926 4.18.0-348.7.1.el8_5.x86_64 #1 SMP Wed Dec 22 13:25:12 UTC 2021 x86_64 Linux
		//截取前2个词
		arr := strings.Split(r, " ")
		return nil, fmt.Sprintf("%s:%s", arr[0], arr[1])
	}
	return nil, ``
}

func GetOsName_windows() (error, string) {
	version, err := windows.GetVersion()
	if err != nil {
		return fmt.Errorf("获取系统信息失败:%s", err.Error()), ``
	}

	major := byte(version & 0xFF)
	minor := byte((version >> 8) & 0xFF)
	build := uint16((version >> 16) & 0xFFFF)

	return nil, fmt.Sprintf("Windows: %d.%d (Build %d)", major, minor, build)
}

func SetMtu(name string) error {
	_, err := run("ip", "link", "set", "mtu", "1280", "up", "dev", name)
	if err != nil {
		return fmt.Errorf("set mtu 失败:%s", err.Error())
	}
	return nil
}
func SetPersistentKeepalive(name, publicKey string) error {
	_, err := run(`wg`, `set`, name, `peer`, publicKey, `persistent-keepalive`, `25`)
	//_, err := run_windows("wg","set",name ,"peer",publicKey,"persistent-keepalive","25",)
	if err != nil {
		return fmt.Errorf("set persistent-keepalive 失败:%s", err.Error())
	}
	return nil
}
